package game;

import game.combat.CombatAppState;
import misc.Vector3i;
import player.AIPlayer;
import player.HumanPlayer;
import board.Board;
import character.CharacterSize;
import character.MyCharacter;
import character.ai.AILogicSettings;
import character.ai.ThreatEvaluation;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.BulletAppState.ThreadingType;
import com.jme3.font.BitmapText;
import com.jme3.light.AmbientLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.system.AppSettings;
import de.lessvoid.nifty.Nifty;
import game.combat.GuiAppState;
import game.roam.RoamAppState;
import generator.DungeonCell;
import generator.DungeonCellFloor;
import generator.DungeonCellWall;
import generator.DungeonRoom;
import generator.DungeonTunnel;
import item.Weapon;
import item.WeaponEnum;
import item.WeaponFactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import player.Player;
import ui.HudScreenController;
import ui.JournalScreenController;

public class Main extends SimpleApplication {
    public static BitmapText ticksText;
    public static List<BitmapText> floatingTexts = new ArrayList<BitmapText>();
    public Player compy1;
    public static Iterator<DungeonRoom> dungeonRoomIter;
    public static Iterator<DungeonTunnel> dungeonTunnelIter;
    public static ColorRGBA tunnelColor;
    public static Iterator<DungeonCell> dungeonTunnelCellIter;
    protected float timeSinceLastTick = 0f;

    public static void main(String[] args) {
        Main app = new Main();
        app.preStart();
        app.start();
    }
    
    protected void preStart() {
        Logger.getLogger("").setLevel(Level.WARNING);
	AppSettings cfg = new AppSettings(true);
	cfg.setFrameRate(60); // set to less than or equal screen refresh rate
	//cfg.setVSync(true);   // prevents page tearing - destroying my framerate?
	//cfg.setFrequency(60); // set to screen refresh rate
	cfg.setResolution(800, 600);
	cfg.setFullscreen(false);
	//cfg.setSamples(2);    // anti-aliasing
	cfg.setTitle("My Game"); // branding: window name
	//try {
	  // Branding: window icon
	  //cfg.setIcons(new BufferedImage[]{ImageIO.read(new File("assets/Interface/icon.gif"))});
	//} catch (IOException ex) {
	  //Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Icon missing.", ex);
	//}
	// branding: load splashscreen from assets
	cfg.setSettingsDialogImage("Interface/MySplashscreen.png");
	setShowSettings(false);
	setSettings(cfg);
    }

    @Override
    public void simpleInitApp() {
	initDataStore();
	initBullet();
	initBoard();
        initLight();
        initGui();
	initPlayers();
        initInput();

	addCharacter(DataStore.player, DataStore.board.getRandomTile().getBoardLocation());
	addCharacter(compy1, DataStore.board.getRandomTile().getBoardLocation()); //hardcoded to the first compy player
        
        //init floating text after characters
        for(Player player : GameController.getAllPlayers()) {
            for(MyCharacter character : player.getCharacters()) {
                BitmapText floatingText = new BitmapText(guiFont);
                floatingText.setSize(guiFont.getCharSet().getRenderedSize());
                floatingText.setText(" ");
                guiNode.attachChild(floatingText);
                floatingTexts.add(character.getId(), floatingText);
            }
        }
        
        Weapon club = WeaponFactory.getWeapon(WeaponEnum.CLUB);
        club.setBoardLocation(DataStore.board.getRandomTile().getBoardLocation());
        DataStore.board.addItem(club);
        
        Weapon lance = WeaponFactory.getWeapon(WeaponEnum.LANCE);
        lance.setBoardLocation(DataStore.board.getRandomTile().getBoardLocation());
        DataStore.board.addItem(lance);
        
        //Dungeon dungeon = DungeonGenerator.generateDungeon(1);
        //dungeonRoomIter = new ArrayList<DungeonRoom>(dungeon.getRooms()).iterator();
        //dungeonTunnelIter = new ArrayList<DungeonTunnel>(dungeon.getTunnels()).iterator();
        
        StateSwitcher.init();
    }

    protected void initDataStore() {
	DataStore.stateManager = stateManager;
	DataStore.renderManager = renderManager;
        DataStore.inputManager = inputManager;
	DataStore.assetManager = assetManager;
	DataStore.rootNode = rootNode;

	DataStore.roamAppState = new RoamAppState();
	stateManager.attach(DataStore.roamAppState);
	DataStore.combatAppState = new CombatAppState();
	stateManager.attach(DataStore.combatAppState);
	DataStore.guiAppState = new GuiAppState();
	stateManager.attach(DataStore.guiAppState);
    }

    protected void initBullet() {
	BulletAppState bulletAppState = new BulletAppState();
	bulletAppState.setThreadingType(ThreadingType.PARALLEL);
	getStateManager().attach(bulletAppState);
        bulletAppState.getPhysicsSpace().enableDebug(assetManager);
	DataStore.bulletAppState = bulletAppState;
    }

    protected void initBoard() {
	Board board = new Board();
        rootNode.attachChild(board);
        DataStore.bulletAppState.getPhysicsSpace().addAll(board);
        DataStore.board = board;
    }
    
    protected void initLight() {
        /** A white ambient light source. */ 
        AmbientLight ambient = new AmbientLight();
        ambient.setColor(ColorRGBA.White);
        rootNode.addLight(ambient);
    }
    
    protected void initGui() {
        setDisplayFps(false); // to hide the FPS
        setDisplayStatView(false); // to hide the statistics
        
        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort);
        Nifty nifty = niftyDisplay.getNifty();
        DataStore.nifty = nifty;
        nifty.addXml("Interface/hud.xml");
        nifty.addXml("Interface/journal.xml");
        nifty.gotoScreen("hud");
        stateManager.attach((HudScreenController)nifty.getScreen("hud").getScreenController());
        stateManager.attach((JournalScreenController)nifty.getScreen("journal").getScreenController());
        ((HudScreenController)nifty.getScreen("hud").getScreenController()).setEnabled(false);
        ((JournalScreenController)nifty.getScreen("journal").getScreenController()).setEnabled(false);
        guiViewPort.addProcessor(niftyDisplay);
        
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        ticksText = new BitmapText(guiFont);
        ticksText.setSize(guiFont.getCharSet().getRenderedSize());
        ticksText.setText(" ");
        ticksText.setLocalTranslation(0, 600, 0);
        guiNode.attachChild(ticksText);
    }

    protected void initPlayers() {
        HumanPlayer human1 = new HumanPlayer("Human1", cam);
        GameController.registerPlayer(human1);
        DataStore.player = human1;
        
        compy1 = new AIPlayer("Compy");
        GameController.registerPlayer(compy1);
        
        for(Player playerOuter : GameController.getAllPlayers()) {
            for(Player playerInner : GameController.getAllPlayers()) {
                if(playerOuter.getClass().equals(playerInner.getClass())) {
                    playerOuter.addRelationship(playerInner, PlayerRelationship.FRIENDLY);
                } else {
                    playerOuter.addRelationship(playerInner, PlayerRelationship.HOSTILE);
                }
            }
        }
    }
    
    protected void initInput() {
        flyCam.setDragToRotate(true);
	flyCam.setMoveSpeed(10f);
	cam.setLocation(new Vector3f(-9f, 57f, 42f));
	cam.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);
        
        InGameInputHandler inGameInput = new InGameInputHandler();
        inGameInput.register();
    }

    protected MyCharacter addCharacter(Player player, Vector3i location) {
        MyCharacter character;
        if(player instanceof AIPlayer)
            character = new MyCharacter(CharacterSize.SINGLE, player, getDefaultAILogicSettings());
        else
            character = new MyCharacter(CharacterSize.SINGLE, player);
        character.setBoardLocation(location);
        character.warpToBoardLocation();
	DataStore.board.addCharacter(character);
	return character;
    }
    
    protected AILogicSettings getDefaultAILogicSettings() {
        AILogicSettings logicSettings = new AILogicSettings();
        logicSettings.setFleeAtPercent(20);
        logicSettings.setThreatEvaluation(ThreatEvaluation.MOST_DAMAGE);
        return logicSettings;
    }

    @Override
    public void simpleUpdate(float tpf) {
	DataStore.board.reduceParticleEffects(tpf);

	timeSinceLastTick += tpf;
	if(timeSinceLastTick >= DataStore.TIME_PER_TICK) {
	    if(dungeonRoomIter != null && dungeonRoomIter.hasNext()) {
                ColorRGBA roomColor = ColorRGBA.randomColor();
                for(DungeonCell cell : dungeonRoomIter.next().getCells()) {
		    if(cell instanceof DungeonCellFloor)
			DataStore.board.addTileAtLocation(cell.getLocation()).highlight(roomColor);
		    else if(cell instanceof DungeonCellWall)
			DataStore.board.addTileAtLocation(cell.getLocation()).highlight(ColorRGBA.Brown);
                }
            } else {
                if(dungeonTunnelCellIter != null && dungeonTunnelCellIter.hasNext()) {
		    DungeonCell cell = dungeonTunnelCellIter.next();
		    if(cell instanceof DungeonCellFloor)
			DataStore.board.addTileAtLocation(cell.getLocation()).highlight(tunnelColor);
		    else if(cell instanceof DungeonCellWall)
			DataStore.board.addTileAtLocation(cell.getLocation()).highlight(ColorRGBA.Brown);
                } else if(dungeonTunnelIter != null && dungeonTunnelIter.hasNext()) {
                    dungeonTunnelCellIter = new ArrayList<DungeonCell>(dungeonTunnelIter.next().getCells()).iterator();
                    tunnelColor = ColorRGBA.randomColor();
                }
            }
	    timeSinceLastTick = 0f;
        }
    }
}
